home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / cc03.arc / LS.C < prev    next >
Text File  |  1986-03-14  |  15KB  |  632 lines

  1. /* ls - a Unix-like directory listing program for MS-DOS 2.x
  2.  *
  3.  * Copyright (c) 1984  R. Edward Nather
  4.  *
  5.  */
  6.  
  7. #include <stdio.h>
  8. #define CIC86
  9.  
  10. /* customizing constants */
  11.  
  12. #define QS       '\\'            /* filename separator character */
  13. #define DQS       "\\"            /* filename separator (string) */
  14. #define ID         0            /* always identify directory if 1 */
  15. #define ALL     0            /* show hidden files by default if 1 */
  16. #define LONG     0            /* long listing by default if 1 */
  17. #define COLM     0            /* 1-column listing by default if 1 */
  18. #define RSORT    0            /* reverse sort by default if 1 */
  19. #define TSORT    0            /* time sort by default if 1 */
  20. #define DU        0            /* include disk use by default if 1 */
  21.  
  22.  
  23. #define NAMESIZ 13            /* 12 character name + NULL */
  24. #define ONECS 512            /* cluster size on one-sided floppy */
  25. #define TWOCS 1024            /* cluster size on two-sided floppy */
  26. #define HARDCS 4096            /* cluster size on hard disk */
  27. #define SCRSIZ 22            /* scrolling size of display screen */
  28.  
  29. struct dta                    /* DOS Disk Transfer Address table */
  30.     {
  31.     char reserved[21];        /* used in "find next" operation */
  32.     char attr;                /* file attribute byte */
  33.     int ftime;                /* time of last modification */
  34.     int fdate;                /* date of last modification */
  35.     long fsize;                /* file size in bytes */
  36.     char fname[NAMESIZ];    /* filename and extension */
  37.     };
  38.  
  39. struct outbuf                /* output buffer -- array of file structs */
  40.     {
  41.     unsigned oattr;
  42.     unsigned odate;
  43.     unsigned otime;
  44.     long osize;
  45.     char oname[NAMESIZ+1];
  46.     } *obuf;
  47.  
  48. char spath[80];                /* holds current pathname string */
  49.  
  50. /* global variables and flags */
  51.  
  52. int allf = ALL;                /* include hidden & system files */
  53. int ll = LONG;                /* long listing */
  54. int colm = COLM;            /* 1-column format */
  55. int rev = RSORT;            /* reverse sort */
  56. int tsrt = TSORT;            /* timesort the listing */
  57. int usage = DU;                /* print disk usage */
  58. int recd;                    /* recursive descent requested */
  59. int sizonly;                /* only print sizes */
  60.  
  61. int np;                        /* number of groups printed */
  62. int nargs;                    /* number of non-option arguments */
  63. int clsize = 0;                /* size of a cluster, in bytes */
  64. int clmask;                    /* clsize-1 for rounding & chopping */
  65. int drive;                    /* code number for drive requested */
  66. int tsc;                    /* 1 if output is to console screen */
  67. long left;                    /* unused space left on disk */
  68. long total;                    /* total of sizes encountered */
  69.  
  70. main(argc, argv)
  71. int argc;
  72. char *argv[];
  73. {
  74. char *s;
  75. int c = 0;
  76. int nt = 0;
  77.  
  78. /* process input options */
  79.  
  80. while(--argc > 0 && (*++argv)[0] == '-') {
  81.     for(s = argv[0]+1; *s != '\0'; s++) {
  82.         switch(tolower(*s)) {
  83.             case 'a':                    /* -a: list all files */
  84.                 allf = (allf == 0);        /* reverse default value */
  85.                 break;
  86.             case 'c':                    /* -c: 1-column listing requested */
  87.                 colm = (colm == 0);
  88.                 break;
  89.             case 'l':                    /* -l: long listing requested */
  90.                 ll = (ll == 0);
  91.                 break;
  92.             case 'r':                    /* -r: reverse sort direction */
  93.                 rev = (rev == 0);
  94.                 break;
  95.             case 's':                    /* -s: print sizes only */
  96.                 sizonly = 1;
  97.                 if(*(s+1) == '1') {
  98.                     clsize = ONECS;        /* diskuse for 1-sided floppy */
  99.                     s++;
  100.                     nt++;
  101.                     }
  102.                 else if(*(s+1) == '2') {
  103.                     clsize = TWOCS;            /* or 2-sided */
  104.                     s++;
  105.                     nt++;
  106.                     }
  107.                 break;
  108.             case 't':                    /* -t: time sort requested */
  109.                 tsrt = (tsrt == 0);
  110.                 break;
  111.             case 'u':                    /* -u: print disk usage */
  112.                 usage = (usage == 0);    
  113.                 break;
  114.             case 'R':                    /* -R: recursively list subdirs */
  115.                 recd = 1;
  116.                 break;
  117.             default:
  118.                 fprintf(stderr, "unknown arg %c\n", *s);
  119.                 exit(1);
  120.             }
  121.         }
  122.     }
  123.  
  124. nargs = argc;
  125. tsc = toscreen();            /* find out if output is to console screen */
  126. obuf = (struct outbuf *)malloc(sizeof(*obuf));    /* point to free memory */
  127.  
  128. if(argc == 0) {
  129.     argc++;
  130.     curdrv(spath);                    /* default to current drive */
  131.     }
  132. else
  133.     strcpy(spath, *argv);
  134.  
  135. for(;;) {                            /* cycle through args present */
  136.     if(spath[1] == ':' && spath[2] == '\0')        /* if drive only */
  137.         getpath(spath);                            /* get path */
  138.     if(usage || sizonly || ll)
  139.         c = getsize(spath);            /* get use data only if needed */
  140.     if(c == 0)
  141.         search(spath);                /* go do the hard work */
  142.     if(--argc > 0)
  143.         strcpy(spath, *++argv);
  144.     else {
  145.         if(usage || sizonly) {
  146.             if(np > 1) {
  147.                 fprintf(stdout, "-------\n%7ld bytes total", total);
  148.                 if(!nt)
  149.                     fputs("; ", stdout);
  150.                 }
  151.             if(!nt)
  152.                 fprintf(stdout, "%7ld bytes left on drive %c\n",
  153.                     left, drive+'a');
  154.             }
  155.         return;
  156.         }
  157.     }
  158. }
  159.  
  160. getsize(path)        /* get file cluster size */
  161. char *path;
  162. {
  163. if(clsize == 0)                            /* if size not already set */
  164.     if((clsize = getcl(path)) == 0) {    /* get cluster size for drive */
  165.         fprintf(stderr,
  166.          "Invalid drive: %c\n", *path);
  167.         return(1);
  168.         }
  169. clmask = clsize-1;
  170. return(0);
  171. }
  172.  
  173. /* toscreen - find out if output is to console screen */
  174.  
  175. toscreen()
  176. {
  177. struct { unsigned int ax, bx, cx, dx, si, di, ds, es; 
  178.        } r;
  179.  
  180. r.ax = 0x4400;
  181. r.bx = 1;
  182. sysint(0x21, &r, &r);
  183. return(r.dx & 1);
  184. }
  185.  
  186. /* search - search 'path' for filename or directory */
  187.  
  188. search(path)
  189. char *path;
  190. {
  191. struct dta dta;                    /* DOS file data table */
  192. extern struct outbuf;            /* array of file structs */
  193. extern int nargs;                /* number of files or directories */
  194. int path_len;                    /* length of initial path */
  195. int z;                            /* char counter */
  196. int k = 0;                        /* counts number of entries found */
  197. char work[80];                    /* working path string */
  198. int comp();                        /* string, time comparison routine */
  199. int mask = 0x0010;                /* attribute mask */
  200. long bytes = 0;                    /* count of disk usage this directory */
  201.  
  202. if(allf)
  203.     mask = 0x001F;
  204. strcpy(work,path);
  205. path_len = strlen(work);        /* save original path length */
  206.  
  207. if(!find_first(work, &dta, 0) || work[path_len-1] == QS) {
  208.     if(work[path_len-1] != QS) {
  209.         strcat(work, DQS);                /* if path is to a directory */
  210.         path_len++;
  211.         }
  212.     strcat(work,"*.*");                    /* list everything in it */
  213.     }
  214.  
  215. if(find_first(work, &dta, mask)) {
  216.     do {
  217.         if(dta.attr & 0x08)                    /* ignore volume label */
  218.             continue;
  219.         if(dta.fname[0] == '.' && !allf)    /* unless -a option */
  220.             continue;                        /* ignore "." and ".." */
  221.  
  222.         obuf[k].oattr = dta.attr;            /* stash this entry */
  223.         obuf[k].otime = dta.ftime;
  224.         obuf[k].odate = dta.fdate;
  225.         obuf[k].osize = dta.fsize;
  226.         strcpy(obuf[k].oname, dta.fname);
  227.  
  228.         if(usage || sizonly) {
  229.             if((dta.attr & 0x10) && dta.fname[0] != '.') {
  230.                 bytes += clsize;                /* sum up disk usage */
  231.                 }
  232.             else if(dta.fsize) {
  233.                 obuf[k].osize = ((dta.fsize + clmask) & (long)(~clmask));
  234.                 bytes += obuf[k].osize;
  235.                 }
  236.             }
  237.  
  238.         k++;
  239.         } while(find_next(&dta));
  240.     }
  241. else {
  242.     work[path_len-1] = NULL;
  243.     fprintf(stderr, "Can't find a file or directory named \"%s\"\n", work);
  244.     return;
  245.     }
  246.  
  247. work[path_len] = NULL;                        /* restore directory pathname */
  248. if(np++ && !sizonly)
  249.     fputc(endlin(),stdout);                            /* separate listing blocks */
  250. if(usage || sizonly) {
  251.     total += bytes;                                    /* total bytes to date */
  252.     fprintf(stdout, "%7ld  ", bytes);
  253.     }
  254. if(recd || nargs > 1 || usage || sizonly || ID) {
  255.     fprintf(stdout, "%s", work);                    /* identify the block */
  256.     fputc(endlin(),stdout);
  257.     }
  258. if(!sizonly) {
  259.     qsort(obuf,k,sizeof(obuf[0]),comp);                /* sort the entries */
  260.     if(ll)
  261.         longlist(k);                                /* and print them */
  262.     else
  263.         shortlist(k);
  264.     }
  265. if(!recd)
  266.     return;                                            /* quit if not -R */
  267. strcat(work, "*.*");
  268. if(find_first(work, &dta, mask))                /* else find all sub-dirs */
  269.     do    {
  270.         if(dta.attr & 0x10 && dta.fname[0] != '.') {
  271.             work[path_len] = 0;                        /* discard old name */
  272.             for(z=0; dta.fname[z] != NULL; z++)
  273.                 dta.fname[z] = tolower(dta.fname[z]);
  274.             strcat(work, dta.fname);                /* install a new one */
  275.             strcat(work, DQS);
  276.             search(work);                            /* and recurse */
  277.             }
  278.     } while(find_next(&dta));
  279. return;
  280. }
  281.  
  282. /* find_first - find first file in chosen directory */
  283.  
  284. find_first(path, dta, mask)
  285. char *path;
  286. struct dta *dta;
  287. int mask;
  288. {
  289. struct { int ax, bx, cx;
  290.          char *dx;
  291.          int si, di, ds, es;
  292.        } r;
  293. extern int _showds();
  294.  
  295. r.ax = 0x1A00;                            /* DOS interrupt 1A */
  296. r.dx = (char *)dta;
  297. r.ds = _showds();
  298. sysint(0x21, &r, &r);                    /* sets data transfer address */
  299.  
  300. r.ax = 0x4E00;                            /* DOS interrupt 4E */
  301. r.cx = mask;        
  302. r.dx = path;
  303. r.ds = _showds();
  304. return(!(sysint(0x21, &r, &r) & 1));    /* fills the structure */
  305. }
  306.  
  307. /* find_next - find the next file in the same directory */
  308.  
  309. find_next(dta)
  310. struct dta *dta;
  311. {
  312. struct { int ax, bx, cx;
  313.          char *dx;
  314.          int si, di, ds, es;
  315.        } r;
  316. extern int _showds();
  317.  
  318. r.ax = 0x1A00;
  319. r.dx = (char *)dta;
  320. r.ds = _showds();
  321. sysint(0x21, &r, &r);                            /* set dta */
  322.  
  323. r.ax = 0x4F00;
  324. return(!(sysint(0x21, &r, &r) & 1));            /* fill the table */
  325. }
  326.  
  327. /* curdrv - get current default drive */
  328.  
  329. curdrv(sp)
  330. char *sp;
  331. {
  332. struct { int ax, bx, cx;
  333.          char *dx, *si, *di, *ds, *es;
  334.        } r;
  335.  
  336. r.ax = 0x1900;                            /* DOS interrupt 19 */
  337. sysint(0x21, &r, &r);                    /* gets current drive number */
  338. *sp++ = r.ax + 'a';                        /* convert to symbolic drive name */
  339. *sp++ = ':';
  340. return;
  341. }
  342.  
  343. /* getpath - get path to directory on indicated drive */
  344.  
  345. getpath(sp)
  346. char *sp;
  347. {
  348. struct { int ax, bx, cx, dx;
  349.          char *si;
  350.          int di, ds, es;
  351.        } r;
  352. extern int _showds();
  353.  
  354. strcat(sp, DQS);            /* append root file symbol to drive name */
  355.  
  356. r.ax = 0x4700;                /* DOS interrupt 47 gets path string */
  357. r.dx = *sp - '`';            /* convert drive name to index */
  358. r.ds = _showds();
  359. r.si = sp + 3;                /* paste string after root symbol */
  360. sysint(0x21, &r, &r);
  361. return;
  362. }
  363.  
  364. /* getcl - get cluster size & space left on requested drive */
  365.  
  366. getcl(pp)
  367. char *pp;
  368. {
  369. struct { int ax, bx, cx, dx, si, di, ds, es;} r;
  370. int cs;
  371. extern long left;
  372. extern int drive;
  373.  
  374. if(*(pp+1) == ':')                    /* use specified drive if any */
  375.     r.ax = *pp - 'a';
  376. else {
  377.     r.ax = 0x1900;                    /* else get code for default drive */
  378.     sysint(0x21, &r, &r);
  379.     }
  380. drive = r.ax & 0x7F;
  381. if(!usage && !sizonly && drive == 2) 
  382.     return(HARDCS);
  383. else {
  384.     r.dx = drive + 1;                /* 0 = default, 1 = a, etc */
  385.     r.ax = 0x3600;
  386.     sysint(0x21, &r, &r);            /* DOS interrupt hex 36 */
  387.     if(r.ax == 0xFFFF)                /* gets free disk space */
  388.         return(0);                    /* and other goodies */
  389.     else {
  390.         cs = r.ax * r.cx;            /* r.ax = sectors/cluster */
  391.         left = (long)cs * r.bx;        /* r.bx = # unused clusters */
  392.         return(cs);                    /* r.cx = bytes/sector */
  393.         }                            /* r.dx = drive capacity (clusters) */
  394.     }
  395. }
  396.  
  397. /* comp - compare size of two entries */
  398.  
  399. comp(a,b)
  400. struct outbuf *a, *b;
  401. {
  402. int y;
  403.  
  404. if(tsrt) {
  405.     if(a->odate != b->odate)                    /* if dates differ */
  406.         y = (a->odate < b->odate) ? -1 : 1;        /* that settles it */
  407.     else
  408.         y = (a->otime < b->otime) ? -1 : 1;        /* else compare times */
  409.     return((rev) ? y : -y);
  410.     }
  411. else {
  412.     y = strcmp(a->oname, b->oname);                /* name comparison */
  413.     return((rev) ? -y : y);
  414.     }
  415. }
  416.  
  417. /* shortlist - print a list of names in 5 columns */
  418.  
  419. shortlist(k)
  420. int k;                    /* total number to print */
  421. {
  422. int i, m, n;
  423.  
  424. if(colm)
  425.     n = k;                /* set for 1-column listing */
  426. else
  427.     n = (k + 4)/5;        /* or 5-column */
  428.  
  429. for(i=0; i < n; i++){
  430.     for(m = 0; (i+m) < k; m += n) {
  431.         if(obuf[i+m].oattr & 0x10)
  432.             strcat(obuf[i+m].oname, DQS);        /* mark directories */
  433.         putname(i+m);                            /* print the name */
  434.         fputs("   ", stdout);        
  435.         }
  436.     fputc(endlin(),stdout);
  437.     }
  438. return;
  439. }
  440.  
  441. /* putname - convert name to lower case and print */
  442.  
  443. putname(i)
  444. int i;
  445. {
  446. int c, j = 0;
  447.  
  448. while((c = tolower(obuf[i].oname[j])) != 0) {
  449.     fputc(c, stdout);
  450.     j++;
  451.     }
  452. while(j++ < NAMESIZ - 1)                    /* pad to columnarize */
  453.     fputc(' ', stdout);
  454. }
  455.  
  456. /* endlin - end a line and watch for screen overflow */
  457.  
  458. static int lc = 0;                    /* line counter */
  459.  
  460. endlin(fp)
  461. FILE *fp;
  462. {
  463. extern int tsc;                            /* true if output is to screen */
  464. int c;
  465.  
  466. if(tsc && ++lc >= SCRSIZ) {            /* pause if output is to console screen */
  467.     fputs("\n\033[7m--More--", fp);            /* and we've shown a screenful */
  468.     c = ci();
  469.     fputs("\033[0m\b\b\b\b\b\b\b\b        \b\b\b\b\b\b\b", fp);
  470.     switch(c) {
  471.         case '\r':                    /* <RETURN> - show 1 more line */
  472.             lc = SCRSIZ - 1;
  473.             break;
  474.         case 'q':                    /* quit with "q" or "ctrl-C" */
  475.         case '\003':
  476.             exit(0);
  477.         default:
  478.             lc = 0;                    /* else show another screenful */
  479.             break;
  480.         }
  481.     return('\b');
  482.     }    
  483. else
  484.     return('\n');
  485. }
  486.  
  487. /* longlist - list everything about files in two columns */
  488.  
  489. struct llst {                /* structure to hold file information */
  490.     char *fattr;            /* file attribute pointer */
  491.     long size;                /* file size */
  492.     int day;                /* the day of creation */
  493.     int mnum;                /* month number */
  494.     int yr;
  495.     int hh;                    /* creation times */
  496.     int mm;
  497.     int ap;                    /* am or pm */
  498.     } l;
  499.  
  500. longlist(k)
  501. int k;            /* total number to list */
  502. {
  503.  
  504. int i, m, n, cdate;
  505. char *mon, *mname();
  506.  
  507. cdate = gcdate();                        /* get current date (in months) */
  508. if(colm)
  509.     n = k;                                /* set for 1 column listing */
  510. else
  511.     n = (k + 1)/2;                        /* or for 2 column listing */
  512. for(i=0; i < n; i++){
  513.     for(m = 0; (m+i) < k; m += n) {        
  514.         fill(i+m, &l);                            /* fill llst structure */
  515.         mon = mname(l.mnum);                    /* conv month # to name */
  516.         fprintf(stdout, "%s%7ld  %2d %s ",
  517.             l.fattr, l.size, l.day, mon);
  518.         if(cdate >= (l.yr * 12 +l.mnum) + 12)
  519.             fprintf(stdout, " %4d  ", l.yr);    /* print year if too old */
  520.         else {
  521.             fprintf(stdout, "%2d:%02d%c ",
  522.                 l.hh, l.mm, l.ap);                /* else print time */
  523.             }
  524.         putname(i+m);
  525.         if(m+n < k)
  526.             fputs("\272 ", stdout);                /* double bar separator */
  527.         }
  528.     fputc(endlin(),stdout);
  529.     }
  530. return;
  531. }
  532.  
  533. /* fill - fill long list structure with file information */
  534.  
  535. fill(i, ll)
  536. int i;
  537. struct llst *ll;
  538. {
  539. int j, k;
  540. static char fbuf[16][4] = {
  541.     "--w",
  542.     "---",
  543.     "-hw",
  544.     "-h-",
  545.     "s-w",
  546.     "s--",
  547.     "shw",
  548.     "sh-",
  549.     "d-w",
  550.     "d--",
  551.     "dhw",
  552.     "dh-",
  553.     "d-w",
  554.     "d--",
  555.     "dhw",
  556.     "dh-"
  557.     };
  558.  
  559. if((obuf[i].oattr & 0x10) && obuf[i].oname[0] != '.') {
  560.     ll->size = clsize;
  561.     j = 8;                                /* if directory, use block size */
  562.     }                                    /* and set dir attr offset */
  563. else {
  564.     ll->size = obuf[i].osize;            /* else use file size */
  565.     j = 0;                                /* and file attr offset */
  566.     }
  567. ll->fattr = fbuf[(obuf[i].oattr & 0x07) + j];    /* point to symbolic attr */
  568. ll->day = obuf[i].odate & 0x1F;
  569. ll->mnum = (obuf[i].odate >> 5) & 0x0F;
  570. ll->yr = (obuf[i].odate >> 9) + 1980;
  571. k = obuf[i].otime >> 5;                            /* this is a mess */
  572. ll->mm = k & 0x3f;
  573. ll->ap = ((ll->hh = k >> 6) >= 12) ? 'p' : 'a';
  574. if(ll->hh > 12)
  575.     ll->hh -= 12;
  576. if(ll->hh == 0)
  577.     ll->hh = 12;
  578. return;
  579. }
  580.  
  581.  
  582. /* gcdate - get current date (in months) for comparison */
  583.  
  584. gcdate()
  585. {
  586. struct { unsigned int ax, bx, cx, dx, si, di, ds, es;} r;
  587.  
  588.     r.ax = 0x2A00;
  589.     sysint(0x21, &r, &r);
  590.     return(r.cx * 12 + (r.dx >> 8));    /* yr * 12 + month */
  591. }
  592.  
  593. /* mname - convert month number to month name */
  594.  
  595. char *mname(n)
  596. int n;
  597. {
  598. static char *name[] = {
  599.     "???",
  600.     "Jan",
  601.     "Feb",
  602.     "Mar",
  603.     "Apr",
  604.     "May",
  605.     "Jun",
  606.     "Jul",
  607.     "Aug",
  608.     "Sep",
  609.     "Oct",
  610.     "Nov",
  611.     "Dec"
  612.     };
  613. return((n < 1 || n > 12) ? name[0] : name[n]);
  614. }
  615.  
  616. #ifdef CIC86
  617.  
  618. _showds()
  619. {
  620. struct{int cs, ss, ds, es;} r;
  621.  
  622. segread(&r);
  623. return(r.ds);
  624. }
  625.  
  626. ci()
  627. {
  628. return(bdos(7) & 0xFF);
  629. }
  630.  
  631. #endif
  632.